﻿
#include "TcpClient.h"
#include "as_connector.h"
#include "TcpConnection.h"
#include "epoll_watch.h"
#include "byte_buffer.h"
#include "log.h"
#include <iostream>

using namespace as::md;
as::net::TcpClient::TcpClient(std::shared_ptr<EpollWatch> &ep, const Address& serverAddr, 
	const std::string_view &name)
	:ep_(ep), svr_name_(name), local_addr_(serverAddr)
{
	connector_ = std::make_unique<Connector>(ep, local_addr_);
	connector_->SetNewConnCb(std::bind(&TcpClient::HandleNewConn, this, std::placeholders::_1));
}

as::net::TcpClient::TcpClient(std::shared_ptr<EpollWatch> &ep, const std::string_view &host, 
	int port, const char* name) 
	:TcpClient(ep, Address(host, port), name)
{

}

as::net::TcpClient::~TcpClient()
{

}

void as::net::TcpClient::Start()
{
	Connect();
	is_stop_ = false;
}

void as::net::TcpClient::Stop()
{
	Disconnect();
	is_stop_ = true;
}

bool as::net::TcpClient::IsStop()
{
	return is_stop_;
}

bool as::net::TcpClient::SendMsg(const char* buf, int size)
{
	if (connection_)
	{
		connection_->SendMsg(buf, size);
		return true;
	}
	return false;
}

bool as::net::TcpClient::SendMsg(ByteBuffer& buf)
{
	if (connection_)
	{
		connection_->SendMsg(buf);
		return true;
	}
	return false;
}

bool as::net::TcpClient::SendMsg(ByteBufferPtr& buf)
{
	if (connection_)
	{
		connection_->SendMsg(buf);
		return true;
	}
	return false;
}

void as::net::TcpClient::Connect()
{
	connect_ = true;
	connector_->start();
}

void as::net::TcpClient::Disconnect()
{
	connect_ = false;
	if (connection_)
	{
		connection_->Shutdown();
	}
}

as::net::TcpClient* as::net::TcpClient::SetConnCb(ConnChangeCb fun)
{
	conn_change_cb_ = fun;
	return this;
}

as::net::TcpConnectionPtr as::net::TcpClient::GetConn()
{
	return connection_;
}

int as::net::TcpClient::GetConnId()
{
	return GetConn() ? GetConn()->GetConnId() : 0;
}

void as::net::TcpClient::SetRepeatConnTime(std::time_t ms)
{
	connector_->SetReConnectTime(ms);
}

void as::net::TcpClient::HandleNewConn(socket_fd fd)
{
	using namespace std::placeholders;

	if (ep_.expired() == false)
	{
		auto ep = ep_.lock();
		Address peerAddr = Socket::get_peer_addr(fd);
		Socket::set_non_block(fd);
		Socket::set_keep_alive(fd);
		std::shared_ptr<TcpConnection> conn = std::make_shared<TcpConnection>(ep, fd, svr_name_, local_addr_, peerAddr);
		conn->SetConnectCallback(conn_change_cb_);
		conn->SetMsgCallback(std::bind(&TcpClient::HandleMsg, this, _1, _2, _3));
		conn->SetCloseCallback(std::bind(&TcpClient::HandleCloseConn, this, _1));
		conn->SetConnId(ep->GenerateConnId());
		{
			std::lock_guard<std::mutex> l(lock_);
			connection_ = conn;
		}

		LOG_DEBUG << "tcp client new fd:" << fd;
		conn->ConnectFinish();
	}
}

void as::net::TcpClient::HandleCloseConn(const TcpConnectionPtr& conn)
{
	if (close_cb_)
	{
		close_cb_(conn);
	}

	{
		std::lock_guard<std::mutex> l(lock_);
		connection_.reset();
	}

	if (ep_.expired() == false)
	{
		auto ep = ep_.lock();
		ep->AddTimer(std::bind(&TcpConnection::DestoryConn, conn));
	}
	else
	{
		conn->DestoryConn();
	}

	if (connect_ && repeat_)
	{
		connector_->reconnect();
	}
}

void as::net::TcpClient::HandleMsg(TcpConnectionPtr& conn, ByteBufferPtr& buf, int size)
{
	if (msg_cb_)
	{
		msg_cb_(conn, buf, size);
	}
}

as::net::TcpClient* as::net::TcpClient::SetMsgCb(MsgCallback fun)
{
	msg_cb_ = fun;
	return this;
}

as::net::TcpClient* as::net::TcpClient::SetCloseCb(CloseCallback fun)
{
	close_cb_ = fun;
	return this;
}

const char* as::net::TcpClient::GetName()
{
	return svr_name_.c_str();
}


